package com.ev.scm.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;
import com.ev.custom.service.MaterielService;
import com.ev.framework.config.Constant;
import com.ev.framework.config.ConstantForGYL;
import com.ev.framework.il8n.MessageSourceHandler;
import com.ev.framework.utils.DateFormatUtil;
import com.ev.framework.utils.MathUtils;
import com.ev.framework.utils.R;
import com.ev.framework.utils.StringUtils;
import com.ev.scm.dao.InStockAccountingDao;
import com.ev.scm.domain.OutsourcingContractItemDO;
import com.ev.scm.domain.StockInDO;
import com.ev.scm.domain.StockInItemDO;
import com.ev.scm.domain.StockOutItemDO;
import com.ev.scm.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author Kuzi
 * @Date 2020-2-17 13:08
 **/

@Service
public class InStockAccountingServiceImpl implements InStockAccountingService {
    @Autowired
    private MessageSourceHandler messageSourceHandler;
    @Autowired
    private OutsourcingContractItemService outsourcingContractItemService;
    @Autowired
    private StockInItemService stockIntemService;
    @Autowired
    private StockOutItemService stockOutItemService;
    @Autowired
    private StockInService stockInService;
    @Autowired
    private PurchaseExpenseItemService purchaseExpenseItemService;
    @Autowired
    private InStockAccountingDao  inStockAccountingDao;
    @Autowired
    private MaterielService materielService;

    @Autowired
    private  StockService  stockService;

    @Override
    public int getCountOfSignIsO(Map<String, Object> map) {
        return inStockAccountingDao.getCountOfSignIsO(map);
    }
    @Override
    public List<Map<String, Object>> getProcessingCharge(Long stockInItemId) {
        return inStockAccountingDao.getProcessingCharge(stockInItemId);
    }

    @Override
    public List<Map<String, Object>> getBomItem(Long ContractItemId) {
        return inStockAccountingDao.getBomItem(ContractItemId);
    }

    @Override
    public List<StockOutItemDO> getStockOutDetail(Long ContractItemId) {
        return inStockAccountingDao.getStockOutDetail(ContractItemId);
    }

    @Override
    public int batchUpdateStockOutItem(List<StockOutItemDO> stockOutItemDOs) {
        return inStockAccountingDao.batchUpdateStockOutItem(stockOutItemDOs);
    }

    @Override
    public Map<String, Object> getTotalTaxAmountCount(Long stockInItemId) {
        return inStockAccountingDao.getTotalTaxAmountCount(stockInItemId);
    }

    @Override
    public int getAnalysisDate(Map<String, Object> map) {
        return inStockAccountingDao.getAnalysisDate(map);
    }

    @Override
    public R saveAccounting(String detailAccounting) {

        List<StockInItemDO> stockInItemDOs = JSONObject.parseArray(detailAccounting, StockInItemDO.class);
        Long[] itemIds=new  Long[stockInItemDOs.size()];
        for (int i=0;i<stockInItemDOs.size();i++){
            itemIds[i]=stockInItemDOs.get(i).getId();
        }
        boolean b = this.disposeIsClose(itemIds,true);
        if (!b){
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }

        if(stockInItemDOs.isEmpty()){
            return R.error();
        }else{
            for (StockInItemDO stockInItemDO:stockInItemDOs){
                stockIntemService.update(stockInItemDO);
            }
            return R.ok();
        }
    }

    @Override
    public R allocationAmount(Long distributionType,Long[] stockInIds) {

        boolean b = this.disposeIsClose(stockInIds,false);
        if (!b){
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }
        List nowList=new ArrayList();
        for (int i = 0; i < stockInIds.length; i++) {
            nowList.add(stockInIds[i]);
        }
        nowList=new ArrayList(new HashSet(nowList));

        Long[] stockInheadIds=new Long[nowList.size()];
        for (int i = 0; i < nowList.size(); i++) {
            stockInheadIds[i]=Long.valueOf(String.valueOf(nowList.get(i)));
        }
        Map<String,Object> map= new HashMap<>();
        map.put("purchaseId",stockInheadIds);
        //提交的所有id的费用的总和
        int totailTaxAmount = purchaseExpenseItemService.getTotailTaxAmount(map);

        if(Objects.equals(0,totailTaxAmount)) {
            return R.error(messageSourceHandler.getMessage("scm.ocation.contractExpenceIsNull", null));

        }else{
                if(Objects.equals(distributionType, ConstantForGYL.COUNT_DISTRIBUTION)){
                    //按数量
                    changeExpenseOfStockInItem(stockInheadIds,true);
                    return R.ok(messageSourceHandler.getMessage("scm.ocation.contractExpenceIsOkByCount",null));
                }else {
                    changeExpenseOfStockInItem(stockInheadIds,false);
                    return R.ok(messageSourceHandler.getMessage("scm.ocation.contractExpenceIsOkByAmount",null));
                }
        }
    }

    public void  changeExpenseOfStockInItem( Long[] stockInheadIds,Boolean sign){

            for(int j=0;j<stockInheadIds.length;j++){

                //某个采购单关联的所有费用总和
                int totailExprnseAmount = purchaseExpenseItemService.getTotailCountAmount(stockInheadIds[j]);
                if(!Objects.equals(0,totailExprnseAmount)){
                    // 已记录的金额
                    BigDecimal recordAllocatedAmount = BigDecimal.ZERO;
                    BigDecimal totailExprnseAmountBig=new BigDecimal(totailExprnseAmount);
                    Map<String,Object>  map= new HashMap<>();
                    map.put("inheadId",stockInheadIds[j]);
                    //子表明细
                    List<StockInItemDO> listSotockInItem = stockIntemService.list(map);

                    //如果是核算1标记，则将金额和单件还原，并将标记改为分配
                    restoreCountAmount(stockInheadIds[j],listSotockInItem);

                    //某个采购单关联的子表totailAmount,totailCount
                    Map<String, Object> totailCountAmount = stockIntemService.getTotailCountAmount(stockInheadIds[j]);
                    BigDecimal totalCount = MathUtils.getBigDecimal(totailCountAmount.get("totailCount"));
                    BigDecimal totalAmount = MathUtils.getBigDecimal(totailCountAmount.get("totailAmount"));

                    map.clear();
                    List<StockInItemDO> listItemDo=new ArrayList<>();

                    StockInItemDO stockInItemDO;
                    int size = listSotockInItem.size();
                    BigDecimal allocatedAmount;
                    for (int i = 0; i < size; i++) {
                        stockInItemDO = listSotockInItem.get(i);
                        // 最后一个分配的取剩下所有的金额
                        if (i == size - 1) {
                            stockInItemDO.setExpense(totailExprnseAmountBig.subtract(recordAllocatedAmount));
                        }

                        if (sign) {
                            // 按数量占总数比例
                            BigDecimal count = stockInItemDO.getCount();
                            BigDecimal meanValue = count.divide(totalCount, Constant.BIGDECIMAL_ZERO, BigDecimal.ROUND_HALF_UP);
                            allocatedAmount = meanValue.multiply(totailExprnseAmountBig);
                            stockInItemDO.setExpense(allocatedAmount);
                        } else {
                            // 按金额占总数比例
                            BigDecimal amount = stockInItemDO.getAmount();
                            BigDecimal meanValue = amount.divide(totalAmount, Constant.BIGDECIMAL_ZERO, BigDecimal.ROUND_HALF_UP);
                            allocatedAmount = meanValue.multiply(totailExprnseAmountBig);
                            stockInItemDO.setExpense(allocatedAmount);
                        }
                        recordAllocatedAmount = recordAllocatedAmount.add(allocatedAmount);
                        stockInItemDO.setId(stockInItemDO.getId());
                        listItemDo.add(stockInItemDO);
                    }
                    stockIntemService.batchUpdate(listItemDo);
                }
            }
    }

    private void restoreCountAmount(Long stockInId,List<StockInItemDO> listSotockInItem){
        StockInDO stockInDo = stockInService.get(stockInId);
        if(Objects.equals(1,stockInDo.getSign())){

            //还原金额和单件     批量还原金额单价
            List<StockInItemDO> oldStockInItemDos=new ArrayList<>();
            Map<Long, Integer> accuracy = materielService.getAccuracy(listSotockInItem.stream().map(StockInItemDO::getMaterielId).distinct().collect(Collectors.toList())).get(0);

            for(StockInItemDO stockInItemDo:listSotockInItem){

                BigDecimal expense=stockInItemDo.getExpense()==null?BigDecimal.ZERO:stockInItemDo.getExpense();

                if(!Objects.equals(0,expense.compareTo(BigDecimal.ZERO) )){
                    BigDecimal oldAmount=stockInItemDo.getAmount().subtract(expense);
                    stockInItemDo.setAmount(oldAmount);
                    stockInItemDo.setUnitPrice(oldAmount.divide(stockInItemDo.getCount(), accuracy.get(stockInItemDo.getMaterielId()),BigDecimal.ROUND_HALF_UP));
                    oldStockInItemDos.add(stockInItemDo);
                }
            }
            //批量执行还原金额单价
            if(!oldStockInItemDos.isEmpty()){
                stockIntemService.batchUpdate(oldStockInItemDos);
            }
            //主表改为分配
            StockInDO newStockInDo=new StockInDO();
            newStockInDo.setSign(0);
            newStockInDo.setId(stockInId);
            stockInService.update(newStockInDo);
        }
    }


    @Override
   public R disposeBusinessAccounting(Long[] stockInIds){


        boolean b = this.disposeIsClose(stockInIds,false);
        if (!b){
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }
        //判断主表sign是否为1,就略去；为0就计算金额单价回写，并更新主表sign为1
        for(int j=0;j<stockInIds.length;j++){
            StockInDO stockInDo = stockInService.get(stockInIds[j]);
            if(Objects.equals(0,stockInDo.getSign())){
                Map<String,Object>  map= new HashMap<>();
                map.put("inheadId",stockInIds[j]);
                //子表明细
                List<StockInItemDO> listSotockInItem = stockIntemService.list(map);

                List<StockInItemDO> newStockInItemDos=new ArrayList<>();

                Map<Long, Integer> accuracy = materielService.getAccuracy(listSotockInItem.stream().map(StockInItemDO::getMaterielId).distinct().collect(Collectors.toList())).get(0);

                for(StockInItemDO stockInItemDo:listSotockInItem){
                    BigDecimal expense=stockInItemDo.getExpense()==null?BigDecimal.ZERO:stockInItemDo.getExpense();

                    if(!Objects.equals(0,expense.compareTo(BigDecimal.ZERO) )){

                        BigDecimal newAmount=stockInItemDo.getAmount().add(expense);
                        stockInItemDo.setAmount(newAmount);
                        stockInItemDo.setUnitPrice(newAmount.divide(stockInItemDo.getCount(), accuracy.get(stockInItemDo.getMaterielId()),BigDecimal.ROUND_HALF_UP));
                        newStockInItemDos.add(stockInItemDo);
                    }
                }
                if(!newStockInItemDos.isEmpty()){
                    stockIntemService.batchUpdate(newStockInItemDos);
                }
                //主表改为分配
                StockInDO newStockInDo=new StockInDO();
                newStockInDo.setSign(1);
                newStockInDo.setId(stockInIds[j]);
                stockInService.update(newStockInDo);
            }
        }
        return R.ok();
   }


    @Override
    public R disposeAffirmAndBack(Long stockInItemId, String detailAccounting) {

        Long[] ids = {stockInItemId};
        boolean b = this.disposeIsClose(ids, true);
        if (!b) {
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }
        StockInItemDO itemDO = stockIntemService.get(stockInItemId);
        if (itemDO == null) {
            return R.error(messageSourceHandler.getMessage("common.massge.haveNoId", null));
        }

        if (itemDO.getIsChargeOff() != null && itemDO.getIsChargeOff() == 1) {
            return R.error(messageSourceHandler.getMessage("scm.accounting.inStockIsAccountingOver", null));
        }

        JSONArray detailArray = JSONArray.parseArray(detailAccounting);

        JSONArray accountingSources = new JSONArray();

        List<StockOutItemDO> outItemDOS = new ArrayList<>();
//        BigDecimal cost = BigDecimal.ZERO;
        JSONObject j;
        for (Object o : detailArray) {
            JSONObject outStockDetail = (JSONObject) o;
            BigDecimal thisTimeCount = outStockDetail.getBigDecimal("thisTimeCount");
            if (thisTimeCount == null) {
                continue;
            }
            Long id = Long.parseLong(outStockDetail.get("id").toString());
//            BigDecimal unitPrice = outStockDetail.getBigDecimal("unitPrice");
            BigDecimal chargeOffCount = outStockDetail.getBigDecimal("chargeOffCount");

//            cost = cost.add(thisTimeCount.multiply(unitPrice));

            j = new JSONObject();
            j.put("outItemID", id);
            j.put("countOnce", thisTimeCount);
            accountingSources.add(j);

            StockOutItemDO stockOutItemDO = new StockOutItemDO();
            stockOutItemDO.setId(id);
            stockOutItemDO.setChargeOffCount(chargeOffCount.add(thisTimeCount));
            outItemDOS.add(stockOutItemDO);
        }
        if (outItemDOS.size() > 0) {
            stockOutItemService.batchUpdate(outItemDOS);
        }

        //已核销
        StockInDO stockInDO = stockInService.get(itemDO.getInheadId());
        stockInDO.setSign(1);
        stockInService.update(stockInDO);

        StockInItemDO stockInItemDo = new StockInItemDO();
        stockInItemDo.setId(stockInItemId);
        // 委外核销不核销成本
//        stockInItemDo.setCost(cost);
        if (accountingSources.size() > 0) {
            stockInItemDo.setAccountSource(accountingSources.toString());
        }
        stockInItemDo.setIsChargeOff(1);
        stockIntemService.update(stockInItemDo);

        return R.ok();
    }


    /*public void updateOutSourcingInStockExpense( List<StockInItemDO> stockInItemDos){
        List<StockInItemDO> newStockInItemDo=new ArrayList<>();
        Map<Long, Integer> accuracy = materielService.getAccuracy(stockInItemDos.stream().map(StockInItemDO::getMaterielId).distinct().collect(Collectors.toList())).get(0);

        for (StockInItemDO stockInItemDo:stockInItemDos){
            //委外费用子表明细
            Map<String, Object> totalTaxAmountCount = this.getTotalTaxAmountCount(stockInItemDo.getId());
            BigDecimal totailCount=new BigDecimal(totalTaxAmountCount.get("totailCount").toString());
            BigDecimal taxAmount=new BigDecimal(totalTaxAmountCount.get("taxAmount").toString());
            // unitPrice
            stockInItemDo.setExpense((taxAmount.multiply(stockInItemDo.getCount()).divide(totailCount, accuracy.get(stockInItemDo.getMaterielId()),BigDecimal.ROUND_HALF_UP)));
            newStockInItemDo.add(stockInItemDo);
        }
        //批量更新委外入库子表
        stockIntemService.batchUpdate(newStockInItemDo);
    }*/

    @Override
    public R disposeRollbackAccounting(Long[] stockInItemIds) {

        boolean b = this.disposeIsClose(stockInItemIds, true);
        if (!b) {
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }

        //取出所有明细
        Map<String, Object> map = new HashMap<>();
        map.put("id", stockInItemIds);
        List<StockInItemDO> itemDetailById = stockIntemService.getItemDetailById(map);
        List<StockOutItemDO> listStockOutItemDo = new ArrayList<>();
        List<StockInItemDO> newItemDetailById = new ArrayList<>();

        for (StockInItemDO stockInItemDO : itemDetailById) {

            StockInDO stockInDO = stockInService.get(stockInItemDO.getInheadId());
            if (stockInItemDO.getIsChargeOff() == null || stockInItemDO.getIsChargeOff() == 0) {
                // 未核销，未核算状态
                continue;
            }
            if (stockInDO.getSign() == 2 && stockInItemDO.getIsChargeOff() == 0) {
                // 分配未核销
                continue;
            }

            // 已核算
            if (stockInDO.getSign() == 3) {
                //已核算  将金额和单价还原，并将成本和费用更新为0.
//               BigDecimal totailAmout = stockInItemDO.getAmount().subtract(stockInItemDO.getCost().add(stockInItemDO.getExpense()));
//               BigDecimal unitPrice = totailAmout.divide(stockInItemDO.getCount(),Constant.BIGDECIMAL_ZERO,BigDecimal.ROUND_HALF_UP);
//                stockInItemDO.setAmount(totailAmout);
//                stockInItemDO.setUnitPrice(unitPrice);
                stockInItemDO.setAmount(BigDecimal.ZERO);
                stockInItemDO.setUnitPrice(BigDecimal.ZERO);
                stockInItemDO.setExpense(BigDecimal.ZERO);
            }

            String accountSource = stockInItemDO.getAccountSource();
            //[{count:240.00000000, materialId:45}]
            if (accountSource == null) {
                continue;
            }
            JSONArray jsonArray = JSON.parseArray(accountSource);
            for (Object o : jsonArray) {
                JSONObject j = (JSONObject) o;
                Long outItemID = j.getLong("outItemID");
                BigDecimal standCount = j.getBigDecimal("countOnce");
                StockOutItemDO outItemDo = stockOutItemService.get(outItemID);
                if (outItemDo != null) {
                    outItemDo.setChargeOffCount(outItemDo.getChargeOffCount().subtract(standCount));
                    listStockOutItemDo.add(outItemDo);
                }

            }

            stockInItemDO.setCost(BigDecimal.ZERO);
            stockInItemDO.setAccountSource(null);
            stockInItemDO.setMaterialIdCount(null);
            stockInItemDO.setIsChargeOff(0);
            newItemDetailById.add(stockInItemDO);
            stockInDO.setSign(-1);
            stockInService.updateAll(stockInDO);
        }
        //批量更新 入库子表
        if (newItemDetailById.size() > 0) {
            stockIntemService.batchUpdate(newItemDetailById);
        }
        if (listStockOutItemDo.size() > 0) {
            stockOutItemService.batchUpdate(listStockOutItemDo);
        }

        return R.ok();
    }

    @Override
    public R disposeAllocationOutIn(Long[] stockInItemIds){
        boolean b = this.disposeIsClose(stockInItemIds,true);
        if (!b){
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }

        List<StockInItemDO> inItemDos = new ArrayList<>();
        List<Long> stockIds = new ArrayList<>();
        for(Long inItemId:stockInItemIds){
            StockInItemDO inItemDo = stockIntemService.get(inItemId);
            List<Map<String, Object>> processingCharge = this.getProcessingCharge(inItemDo.getId());
            BigDecimal amount;
            if(processingCharge.isEmpty()){
                //取合同单价*入库数量
                OutsourcingContractItemDO outsourcingContractItemDO = outsourcingContractItemService.get(inItemDo.getSourceId());
                if(outsourcingContractItemDO!=null){
                    amount =outsourcingContractItemDO.getUnitPrice().multiply(inItemDo.getCount());
                }else{
                    amount =BigDecimal.ZERO;
                }
            }else{
                //取加工费用金额
                amount =TypeUtils.castToBigDecimal(processingCharge.get(0).get("amount"));
            }
            inItemDo.setExpense(amount);
            inItemDos.add(inItemDo);
            if(!stockIds.contains(inItemDo.getInheadId())){
                stockIds.add(inItemDo.getInheadId());
            }
        }
        stockIntemService.batchUpdate(inItemDos);

        for(Long id : stockIds){
            StockInDO stockInDO=new StockInDO();
            stockInDO.setSign(2);
            stockInDO.setId(id);
            stockInService.update(stockInDO);
        }

        /*for(Long stockInId:stockInIds){
            Map<String,Object>  map= new HashMap<>();
            map.put("inheadId",stockInId);
            List<StockInItemDO> inItemDos = stockIntemService.list(map);
            if(inItemDos==null){
                continue;
            }
            for(StockInItemDO inItemDo:inItemDos){

                List<Map<String, Object>> unitPriceMap = this.getUnitPrice(inItemDo.getId());
                BigDecimal unitPrice;
                if(unitPriceMap.isEmpty()){
                    //取合同单价
                    OutsourcingContractItemDO outsourcingContractItemDO = outsourcingContractItemService.get(inItemDo.getSourceId());
                    if(outsourcingContractItemDO!=null){
                        unitPrice=outsourcingContractItemDO.getUnitPrice();
                    }else{
                        unitPrice=BigDecimal.ZERO;
                    }
                }else{
                    //取加工费用单价w
                    unitPrice=new BigDecimal(unitPriceMap.get(0).get("unitPrice").toString());
                }
                inItemDo.setExpense(inItemDo.getCount().multiply(unitPrice));
            }
            stockIntemService.batchUpdate(inItemDos);

            StockInDO stockInDO=new StockInDO();
            stockInDO.setSign(2);
            stockInDO.setId(stockInId);
            stockInService.update(stockInDO);
        }*/
        return R.ok();
    }

    @Override
    public R disposeAccountingPrice(Long[] stockInItemIds) {

        boolean b = this.disposeIsClose(stockInItemIds, true);
        if (!b) {
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }

        Map<String, Object> map = new HashMap<>();
        map.put("id", stockInItemIds);

        if (this.getCountOfSignIsO(map) > 0) {
            // 未经分配的 sign==-1，初始-1
            return R.error(messageSourceHandler.getMessage("scm.accounting.existNotAllocation", null));
        }
        map.clear();
        map.put("ids", Arrays.asList(stockInItemIds));
        List<StockInItemDO> inItemDos = stockIntemService.list(map);
        Map<Long, Integer> accuracy = materielService.getAccuracy(inItemDos.stream().map(StockInItemDO::getMaterielId).distinct().collect(Collectors.toList())).get(0);
        JSONArray ja;
        JSONObject jo;
        StockOutItemDO stockOutItemDO;
        for (StockInItemDO inItemDo : inItemDos) {
            BigDecimal cost = BigDecimal.ZERO;
            BigDecimal expense = BigDecimal.ZERO;
            String accountSource = inItemDo.getAccountSource();
            // XXX 这里可以优化为一次性查出所有出库单
            if (StringUtils.isNoneEmpty(accountSource)) {
                ja = JSON.parseArray(accountSource);
                for (Object o : ja) {
                    jo = (JSONObject) o;
                    Long outItemID = jo.getLong("outItemID");
                    stockOutItemDO = stockOutItemService.get(outItemID);
                    BigDecimal unitPrice = stockOutItemDO.getUnitPrice();
                    cost = cost.add(unitPrice.multiply(jo.getBigDecimal("countOnce")));
                }
            }
            if (inItemDo.getExpense() != null) {
                expense = inItemDo.getExpense();
            }

            BigDecimal totalAmount = cost.add(expense);
            BigDecimal unitPrice = totalAmount.divide(inItemDo.getCount(), accuracy.get(inItemDo.getMaterielId()), BigDecimal.ROUND_HALF_UP);
            inItemDo.setUnitPrice(unitPrice);
            inItemDo.setCost(cost);
            inItemDo.setAmount(totalAmount);
        }
        if (inItemDos.size() > 0) {
            stockIntemService.batchUpdate(inItemDos);
        }
        List<Long> stockInIds = inItemDos.stream().map(StockInItemDO::getInheadId).distinct().collect(Collectors.toList());
        // XXX 这里可以优化一次性修改
        for (Long id : stockInIds) {
            StockInDO stockInDO = new StockInDO();
            stockInDO.setSign(3);
            stockInDO.setId(id);
            stockInService.update(stockInDO);
        }
        return R.ok();
    }


    @Override
    public R disposeAutoAccounting(Long stockInItemId, String detailAccounting) {

        Long[] ids = {stockInItemId};
        boolean b = this.disposeIsClose(ids, true);
        if (!b) {
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }
        if (StringUtils.isBlank(detailAccounting)){
            return R.error(messageSourceHandler.getMessage("common.massge.haveNoMassge", null));
        }

        JSONArray stockOutItemDos = JSON.parseArray(detailAccounting);

        StockInItemDO stockInItemDo = stockIntemService.get(stockInItemId);
        StockInDO stockInDO = stockInService.get(stockInItemDo.getInheadId());
        // 是否已核销过
        if (stockInItemDo.getIsChargeOff() != null && stockInItemDo.getIsChargeOff() == 1) {
            return R.error(messageSourceHandler.getMessage("scm.accounting.inStockIsAccountingOver", null));
        }

        // 若已核算
        if (stockInDO.getSign() == 3) {
            return R.error(messageSourceHandler.getMessage("scm.checkCount.accountingOver", null));
        }

        // 入库成品数量
        BigDecimal count = stockInItemDo.getCount();
        // 委外合同子表id
        Long contractItemId = stockInItemDo.getSourceId();

        // 应该核销的数量
        List<Map<String, Object>> shouldWriteOffWithBomList = new ArrayList<>();
        List<Map<String, Object>> bomItem = this.getBomItem(contractItemId);
        if (bomItem.isEmpty()) {
            return R.error(messageSourceHandler.getMessage("scm.accounting.haveNoBom", null));
        }

        Map<Long, Integer> accuracy = materielService.getAccuracy(bomItem.stream().map(e -> Long.parseLong(e.get("materielId").toString())).distinct().collect(Collectors.toList())).get(1);
        for (Map<String, Object> map : bomItem) {
            //本次需要核销的数量
            BigDecimal standardCount = new BigDecimal(map.get("standardCount").toString());
            BigDecimal wasteRate = new BigDecimal(map.get("wasteRate").toString());
            BigDecimal planFeeding = standardCount.divide(BigDecimal.valueOf(1 - wasteRate.doubleValue() / 100), accuracy.get(Long.parseLong(map.get("materielId").toString())), BigDecimal.ROUND_HALF_UP);
            BigDecimal needAccountCount = planFeeding.multiply(count);
            map.put("standardCount", needAccountCount);
            shouldWriteOffWithBomList.add(map);
        }

        for (Map<String, Object> bomStandard : shouldWriteOffWithBomList) {
            //需要某一组件物料需要核销的数量
            BigDecimal standardCount = TypeUtils.castToBigDecimal(bomStandard.get("standardCount"));
            //需要核销的物料
            Long materielId = Long.parseLong(bomStandard.get("materielId").toString());

            for (Object o : stockOutItemDos) {
                JSONObject stockOutItemDO = (JSONObject)o;

                if (standardCount.compareTo(BigDecimal.ZERO) == 0) {
                    //需要核销的某物料已被核销完毕，跳出循环，进入下个组物料的分配
                    break;
                }
                // 本次核销的数量
                BigDecimal countOnce = BigDecimal.ZERO;
                if (Objects.equals(materielId, stockOutItemDO.getLong("materielId"))) {
                    //已核销数量
                    BigDecimal chargeOffCount = stockOutItemDO.getBigDecimal("chargeOffCount");
                    if (chargeOffCount == null){
                        chargeOffCount = BigDecimal.ZERO;
                    }
                    //出库单中可以再核销的数量
                    BigDecimal canChargeOffCount = stockOutItemDO.getBigDecimal("count").subtract(chargeOffCount);
                    if (canChargeOffCount.compareTo(BigDecimal.ZERO) == 0) {
                        continue;
                    }

                    // 若标准数量大于等于本次可以再核销的数量 本次核销数量为未核销完的数量
                    if (standardCount.compareTo(canChargeOffCount) > 0) {
                        countOnce = canChargeOffCount;
                        standardCount = standardCount.subtract(canChargeOffCount);
                    }
                    // 若标准数量小于本次可以再核销的数量 本次核销数量为剩余的标准数量 标准数量为0
                    if (standardCount.compareTo(canChargeOffCount) <= 0) {
                        countOnce = standardCount;
                        standardCount = BigDecimal.ZERO;
                    }
                }
                if (!Objects.equals(BigDecimal.ZERO, countOnce)) {
                    stockOutItemDO.put("thisTimeCount", countOnce);
                }

            }
            //记录存在未分配完的物料
//                if (!Objects.equals(BigDecimal.ZERO, standardCount)) {
//                    Map<String, Object> map = new HashMap<>();
//                    map.put("materialId", materielId);
//                    map.put("count", standardCount);
//                    leaveOverMaterials.add(map);
//                }
        }
//            //处理遗留未分配的组件物料
////            if (Objects.nonNull(leaveOverMaterials)) {
////                StockInItemDO stockInItemDO = new StockInItemDO();
////                stockInItemDO.setMaterialIdCount(leaveOverMaterials.toString());
////                stockInItemDO.setId(stockInItemId);
////                stockIntemService.update(stockInItemDO);
////            }
        Map<String, Object> result = new HashMap<>();
        result.put("data", stockOutItemDos);
        return R.ok(result);
    }


    /**
     *关账验证
     * @return {@code true} 未关账
     * predicate, otherwise {@code false}
     */
    @Override
    public boolean disposeIsClose(Long[] itemOrHeadIds, Boolean sign) {
        Map<String, Object> map = new HashMap<>();
        if (sign) {
            map.put("inItemId", itemOrHeadIds);
        } else {
            Long[] distinctIds = Arrays.stream(itemOrHeadIds).distinct().toArray(Long[]::new);
            map.put("stockInId", distinctIds);
        }
        List<Map<String, Object>> inOutTimeList = stockIntemService.getInOutTime(map);
        if (inOutTimeList.isEmpty()) {
            return false;
        }

        Date periodTime = stockService.getPeriodTime();
        if (Objects.equals(periodTime, null)) {
            return false;
        }

        return inOutTimeList.stream().anyMatch(e -> {
            Date inOutTime = DateFormatUtil.getDateByParttern(e.getOrDefault("inOutTime", "").toString(), DateFormatUtil.DATE_PATTERN);
            return inOutTime != null && inOutTime.after(periodTime);
        });
        /*for (Map<String, Object> maps : inOutTimeList) {

            if (Objects.isNull(maps) || !maps.containsKey("inOutTime")) {
                continue;
            }
            Date inOutTime = DateFormatUtil.getDateByParttern(maps.get("inOutTime").toString(), "yyyy-MM-dd HH:mm:ss");
            if (inOutTime.before(periodTime)) {
                return false;
            }
        }
        return true;*/
    }

    @Override
    public R editInStockAccounting(List<StockInItemDO> stockInItemDOs) {
        if (stockInItemDOs == null || stockInItemDOs.size() == 0) {
            return R.error();
        }
        Long[] itemIds = stockInItemDOs.stream().map(StockInItemDO::getId).toArray(Long[]::new);
        boolean b = this.disposeIsClose(itemIds, true);
        if (!b) {
            return R.error(messageSourceHandler.getMessage("scm.stock.haveCarryOver.inventoryNotEnabled", null));
        }
        stockIntemService.batchUpdate(stockInItemDOs);
        return R.ok();
    }


}
